package com.filldream.fastboot.web.controller.pc;

import com.filldream.fastboot.base.request.pc.redisController.AddRedisSTO;
import com.filldream.fastboot.base.request.pc.redisController.ModifyRedisSTO;
import com.filldream.fastboot.base.response.pc.cacheController.CacheDTO;
import com.filldream.fastboot.common.annotation.Log;
import com.filldream.fastboot.common.annotation.PassTokenAnnotation;
import com.filldream.fastboot.common.annotation.RolePermissions;
import com.filldream.fastboot.common.constant.FinalStr;
import com.filldream.fastboot.common.entity.ErrorCode;
import com.filldream.fastboot.common.entity.R;
import com.filldream.fastboot.common.util.Assert;
import com.filldream.fastboot.common.util.RandomUtil;
import com.filldream.fastboot.core.cache.CacheMap;
import com.filldream.fastboot.core.cache.CacheUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.*;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Tuple;
import java.util.*;

/**
 * @author RickSun
 * @version 1.0
 * @data 2021-09-18 16:06
 * @description PcCacheController
 */
@PassTokenAnnotation
@AllArgsConstructor
@Api(tags = "PC-Redis管理")
@RestController
@RequestMapping("/pc/redis")
public class PcCacheController {

    @RolePermissions(value = "redis:cacheMapList")
    @Log(value = "查询存储策略列表")
    @ApiOperation(value = "查询存储策略列表",notes = "")
    @GetMapping("/cacheMapList")
    public R<List<CacheDTO>> cacheMapList(String keyContent)  {
        CacheMap[] values = CacheMap.values();
        List<CacheDTO> result= new ArrayList<>();
        if(StringUtils.isNotBlank(keyContent)){
            keyContent = keyContent.toUpperCase();
        }
        for (CacheMap item : values) {
            if(  StringUtils.isNotBlank(keyContent) && (item.name().contains(keyContent) || item.getKeyRemark().contains(keyContent)) ){
                result.add( new CacheDTO().setKey( item.name()).setValue(item.getKeyRemark() ) );
            }
            if( StringUtils.isBlank(keyContent) ){
                result.add( new CacheDTO().setKey( item.name()).setValue(item.getKeyRemark() ) );
            }
        }
        return R.successd(result);
    }


    @RolePermissions(value = "redis:cacheMapChildList")
    @Log(value = "查询 存储策略 缓存列表")
    @ApiOperation(value = "查询 存储策略 缓存列表",notes = "")
    @GetMapping("/cacheMapChildList")
    public R<List<CacheDTO>> cacheMapChildList( String key ) {
        List<CacheDTO> result = new ArrayList<>();
        Assert.isBoolean( StringUtils.isBlank(key) || key.equals("*") , ErrorCode.BASE_ERR.reMsg("参数有误哦~") );
        String pattern = "";
        try {
            pattern = CacheMap.valueOf(key).getKeyName("*");
        }catch (IllegalArgumentException e){
            Assert.isBoolean( true, ErrorCode.BASE_ERR.reMsg("当前存储策略不存在~") );
        }
        Assert.isEmpty( pattern,"不能搜索全部哦~" );

        try(Jedis jedis  = CacheUtil.getCacheJedis()) {
            Set<String> keys = jedis.keys(pattern);
            for (String item : keys) {
                result.add(new CacheDTO().setKey(item));
            }
        }
        return R.successd(result);
    }


    @RolePermissions(value = "redis:get")
    @Log(value = "查询缓存详情")
    @ApiOperation(value = "查询缓存详情")
    @GetMapping("/get")
    public R<CacheDTO> get( String key ) {
        Assert.isBoolean( StringUtils.isBlank(key) || key.equals("*") || !key.contains(FinalStr.getProject_name()) , ErrorCode.BASE_ERR.reMsg("参数有误哦~") );
        CacheDTO result = new CacheDTO();

        Jedis jedis  = CacheUtil.getCacheJedis();

        try {

            //判断缓存的类型
            String type = jedis.type(key);
            Assert.isBoolean(StringUtils.isBlank(type) || "none".equals(type), ErrorCode.BASE_ERR.reMsg("缓存类型不存在或不支持~"));
            result.setType(type).setKey(key);

            if (type.equals("string")) {
                result = result.setKey(key).setValue(jedis.get(key)).setTotal(1);
            } else if (type.equals("hash")) {
                Map<String, String> redisMap = jedis.hgetAll(key);
                List<Map<String, String>> reList = new ArrayList<>();
                redisMap.forEach((k, v) -> {
                    Map<String, String> itemMap = new HashMap<>();
                    itemMap.put("field", k);
                    itemMap.put("value", v);
                    reList.add(itemMap);
                });
                result.setValue(reList);
                result.setTotal( redisMap.size() );
            } else if (type.equals("set")) {
                Set<String> smembers = jedis.smembers(key);
                result.setValue(smembers).setTotal( smembers.size() );
            } else if (type.equals("zset")) {
                Set<Tuple> tuples = jedis.zrevrangeWithScores(key, 0, -1);
                result.setValue( tuples ).setTotal(tuples.size());
            } else if (type.equals("list")) {
                List<String> lrange = jedis.lrange(key, 0, jedis.llen(key));
                result.setValue(lrange).setTotal( lrange.size() );
            }

            result.setTtl(jedis.ttl(key));
        }finally {
            jedis.close();
        }
        return R.successd(result);
    }

    @RolePermissions(value = "redis:del")
    @Log(value = "删除缓存")
    @ApiOperation(value = "删除缓存")
    @PostMapping("/del")
    public R<Long> del( @RequestBody CacheDTO cacheDTO ) {
        String key = cacheDTO.getKey();
        String type = cacheDTO.getType();
        String value = (String)cacheDTO.getValue();
        Long result = 0L;
        Assert.isBoolean(
                StringUtils.isBlank(key) || key.contains("*") || !key.contains(FinalStr.getProject_name())
                ,ErrorCode.BASE_ERR.reMsg("该缓存键值[ "+ key +" ]不存在或不合法")
        );

        Assert.isBoolean( "none".equals(type),ErrorCode.BASE_ERR.reMsg("当前缓存类型有误~") );

        Jedis jedis  = CacheUtil.getCacheJedis();

        try {
            if (StringUtils.isEmpty(type) || type.equals("string")) {
                result = jedis.del(key);
            } else if (type.equals("list")) {
                String tempValue = "del" + RandomUtil.randAlphaNumString(20);
                jedis.lset(key, cacheDTO.getIndex(), tempValue);
                result = jedis.lrem(key, 0, tempValue);
            } else if (type.equals("hash")) {
                result = jedis.hdel(key, value);
            } else if (type.equals("set")) {
                result = jedis.srem(key, value);
            } else if (type.equals("zset")) {
                result = jedis.zrem(key, value);
            }
        }finally {
            jedis.close();
        }
        return R.successd( result );
    }

    @RolePermissions(value = "redis:modifyTTL")
    @Log(value = "修改缓存TTL")
    @ApiOperation(value = "修改缓存TTL")
    @PostMapping("/modifyTTL")
    public R<Long> modifyTTL( @RequestBody ModifyRedisSTO modifyRedisSTO ) {
        Assert.isBoolean(  modifyRedisSTO.getTtl() == null || modifyRedisSTO.getTtl().equals(0L),ErrorCode.PARAM_ERR.reMsg("TTL错误") );

        //1、校验key是否存在
        String key = modifyRedisSTO.checkKey();
        Jedis jedis  = CacheUtil.getCacheJedis();
        Long expire = -100L;
        try {
            //key是否存在
            Boolean exists = jedis.exists(key);
            Assert.checkBoolean(exists, ErrorCode.BASE_ERR.reMsg(key + " 不存在"));
            //2、设置TTL
            expire = jedis.expire(key, modifyRedisSTO.getTtl().intValue());
        }finally {
            jedis.close();
        }
        return R.successd(expire);

    }

    @RolePermissions(value = "redis:modify")
    @Log(value = "修改缓存")
    @ApiOperation(value = "修改缓存")
    @PostMapping("/modify")
    public R<Boolean> modify( @RequestBody ModifyRedisSTO modifyRedisSTO ) {

        boolean result = false;

        //1、校验key是否存在
        String key = modifyRedisSTO.checkKey();
        Jedis jedis  = CacheUtil.getCacheJedis();

        try {

            Boolean exists = jedis.exists(key);
            Assert.checkBoolean(exists, ErrorCode.BASE_ERR.reMsg(key + " 不存在"));

            //2、校验type
            String type = modifyRedisSTO.getType();
            String redisType = jedis.type(key);
            Assert.checkBoolean(redisType.equals(type), ErrorCode.BASE_ERR.reMsg("该缓存类型不正确，请刷新后重试"));

            //3、根据不同type来处理修改逻辑
            Integer index = modifyRedisSTO.getIndex();
            if (type.equals("list")) {
                Assert.isEmpty(index, ErrorCode.BASE_ERR.reMsg("list 类型下标不能为空！"));
                String lset = jedis.lset(key, index, modifyRedisSTO.getValue());
                result = StringUtils.isNotBlank(lset);
            } else if (type.equals("hash")) {
                Long hset = jedis.hset(key, modifyRedisSTO.getField(), modifyRedisSTO.getValue());
                result = hset > -1L;
            } else if (type.equals("set")) {
                Long sadd = jedis.sadd(key, modifyRedisSTO.getMember());
                result = sadd > -1L;
            } else if (type.equals("zset")) {
                Long zadd = jedis.zadd(key, modifyRedisSTO.getScore(), modifyRedisSTO.getElement());
                result = zadd > -1L;
            } else if (type.equals("string")) {
                String set = jedis.set(key, modifyRedisSTO.getValue());
                result = "OK".equals(set);
            } else {
                Assert.isBoolean(true, ErrorCode.BASE_ERR.reMsg("缓存类型错误或不支持"));
            }
        }finally {
            jedis.close();
        }

        Assert.checkBoolean( result,ErrorCode.BASE_ERR.reMsg("修改失败") );
        return R.successd(result);

    }


    @RolePermissions(value = "redis:add")
    @Log(value = "添加缓存")
    @ApiOperation(value = "添加缓存")
    @PostMapping("/add")
    public R<Boolean> add( @RequestBody AddRedisSTO addRedisSTO ) {

        Long result = null;

        //1、校验key是否存在
        String key = addRedisSTO.checkKey();

        //2、校验type
        String type = addRedisSTO.getType();
        Assert.isBoolean( StringUtils.isBlank(type) || type.equals("none"),ErrorCode.PARAM_ERR.reMsg("缓存类型错误~") );


        Jedis jedis  = CacheUtil.getCacheJedis();

        try {
            //3、根据不同type来处理修改逻辑
            if (type.equals("list")) {
                result = addRedisSTO.getIsLeft() ? jedis.lpush(key, addRedisSTO.getValue()) : jedis.rpush(key, addRedisSTO.getValue());
            } else if (type.equals("hash")) {
                result = jedis.hset(key, addRedisSTO.getField(), addRedisSTO.getValue());
            } else if (type.equals("set")) {
                result = jedis.sadd(key, addRedisSTO.getMember());
            } else if (type.equals("zset")) {
                result = jedis.zadd(key, addRedisSTO.getScore(), addRedisSTO.getElement());
            }
        }finally {
            jedis.close();
        }

        Assert.checkBoolean( result >= 0L ,ErrorCode.BASE_ERR.reMsg("修改失败") );
        return R.successd(true);

    }



    @RolePermissions(value = "redis:info")
    @Log(value = "查询Redis信息")
    @ApiOperation(value = "查询Redis信息")
    @GetMapping("/info")
    public R<Map<String,String>> info(  ) {
        String redisInfo = "";
        Long keys = 0L;
        Map<String,String> resultMap = new HashMap<>();
        resultMap.put( "used_memory_human" ,"/");
        resultMap.put( "redis_version" ,"/");
        resultMap.put( "tcp_port" ,"/");
        resultMap.put( "redis_mode" ,"/");
        resultMap.put( "connected_clients" ,"/");
        resultMap.put( "uptime_in_days" ,"/");
        resultMap.put( "used_cpu_sys_children" ,"/");
        resultMap.put( "aof_enabled" ,"/");
        resultMap.put( "rdb_last_bgsave_status" ,"/");
        resultMap.put( "instantaneous_input_kbps" ,"/");
        resultMap.put( "instantaneous_output_kbps" ,"/");
        resultMap.put( "used_memory_peak_human" ,"/");

        Jedis jedis  = CacheUtil.getCacheJedis();
        try {
            redisInfo = jedis.info();
            keys = jedis.dbSize();
        }finally {
            jedis.close();
        }

        getInfoItem(redisInfo,resultMap);

        //后置处理
        resultMap.put( "dbSize",keys.toString() );
        return R.successd(resultMap);
    }


    private void getInfoItem(String redisInfo,Map<String,String> resultMap) {
        String[] items = redisInfo.split("\r\n");
        for (String item : items) {
            if (item.contains(":")) {
                String[] itemConfig = item.split(":");
                String key = itemConfig[0];
                if (resultMap.containsKey(key)) {
                    resultMap.put(key, itemConfig[1]);
                }
            }
        }
    }

}
